package com.ruoyi.gateway.service.impl;

import com.ruoyi.gateway.domain.dto.MessageFlowRecord;
import com.ruoyi.gateway.service.*;
import lombok.extern.slf4j.Slf4j;
import org.dromara.mica.mqtt.core.server.MqttServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import org.dromara.mica.mqtt.core.annotation.MqttServerFunction;

import javax.annotation.PostConstruct;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
@Slf4j
public class MqttServerServiceImpl implements MqttServerService {

    @Autowired
    private MqttServer mqttServer;

    @Autowired
    private IDeviceMapService deviceMapService;

    @Autowired
    private MqttClientManager mqttClientManager;

    @Autowired
    private GatewayMonitorService monitorService;

    @Autowired
    private ITopicMapService topicMapService;

    @Autowired
    private MessageTransformService messageTransformService;

    // 存储客户端连接状态
    private final Map<String, ClientSession> clientSessions = new ConcurrentHashMap<>();

    @PostConstruct
    public void init() {
//        log.info("MQTT Server服务初始化完成，端口: {}", mqttServer.getServerConfig().getPort());
    }

    /**
     * 处理客户端连接认证
     */
    @MqttServerFunction("$SYS/${clientId}/connected")
    public void handleClientConnect(String topic, Map<String, String> topicVars, byte[] payload) {
        String clientId = topicVars.get("clientId");
        log.info("设备尝试连接: {}", clientId);

        // 验证设备是否存在
        if (!deviceMapService.validateDevice(clientId)) {
            log.warn("设备 {} 验证失败，拒绝连接", clientId);
            // 在实际生产中，这里应该返回连接拒绝
            return;
        }

        // 记录客户端会话
        ClientSession session = new ClientSession();
        session.setClientId(clientId);
        session.setConnectTime(System.currentTimeMillis());
        session.setStatus(ClientSession.Status.CONNECTED);
        clientSessions.put(clientId, session);

        log.info("设备 {} 连接成功", clientId);
        monitorService.recordDeviceConnect(clientId);

        // 创建对应的平台代理客户端
        mqttClientManager.createPlatformClients(clientId);
    }

    /**
     * 处理客户端断开连接
     */
    @MqttServerFunction("$SYS/${clientId}/disconnected")
    public void handleClientDisconnect(String topic, Map<String, String> topicVars, byte[] payload) {
        String clientId = topicVars.get("clientId");
        log.info("设备 {} 断开连接", clientId);

        // 更新客户端会话状态
        ClientSession session = clientSessions.get(clientId);
        if (session != null) {
            session.setStatus(ClientSession.Status.DISCONNECTED);
            session.setDisconnectTime(System.currentTimeMillis());
        }

        monitorService.recordDeviceDisconnect(clientId);

        // 断开对应的平台代理客户端
        mqttClientManager.destroyPlatformClients(clientId);
    }

    /**
     * 处理设备状态上报
     * 主题格式: /jiasion/device/state
     */
    @MqttServerFunction("/jiasion/device/state")
    public void handleDeviceState(String topic, byte[] payload) {
        // 从payload中解析clientId，根据实际消息格式调整
        String clientId = extractClientIdFromPayload(payload);
        if (clientId == null) {
            log.error("无法从消息中解析clientId, topic: {}", topic);
            return;
        }

        handleDeviceMessage(clientId, topic, payload);
    }

    /**
     * 处理设备属性上报
     * 主题格式: /jiasion/device/property
     */
    @MqttServerFunction("/jiasion/device/property")
    public void handleDeviceProperty(String topic, byte[] payload) {
        String clientId = extractClientIdFromPayload(payload);
        if (clientId == null) {
            log.error("无法从消息中解析clientId, topic: {}", topic);
            return;
        }

        handleDeviceMessage(clientId, topic, payload);
    }

    /**
     * 处理设备事件上报
     * 主题格式: /jiasion/device/event
     */
    @MqttServerFunction("/jiasion/device/event")
    public void handleDeviceEvent(String topic, byte[] payload) {
        String clientId = extractClientIdFromPayload(payload);
        if (clientId == null) {
            log.error("无法从消息中解析clientId, topic: {}", topic);
            return;
        }

        handleDeviceMessage(clientId, topic, payload);
    }

    /**
     * 通用设备消息处理
     */
    private void handleDeviceMessage(String clientId, String topic, byte[] payload) {
        log.debug("收到设备消息: clientId={}, topic={}, size={}", clientId, topic, payload.length);

        // 记录消息流水
        MessageFlowRecord record = new MessageFlowRecord();
        record.setClientClientId(clientId);
        record.setDirection("up");
        record.setDeviceTopic(topic);
        record.setMessageContent(new String(payload, StandardCharsets.UTF_8));
        record.setMessageSize(payload.length);
        record.setStatus("processing");
        monitorService.recordMessageFlow(record);

        try {
            // 转发到物联网平台
            boolean success = mqttClientManager.forwardToPlatform(clientId, topic, payload);

            if (success) {
                record.setStatus("success");
                log.debug("设备消息转发成功: clientId={}", clientId);
            } else {
                record.setStatus("failed");
                record.setErrorMessage("转发到平台失败");
                log.error("设备消息转发失败: clientId={}", clientId);
            }
        } catch (Exception e) {
            record.setStatus("failed");
            record.setErrorMessage(e.getMessage());
            log.error("处理设备消息异常: clientId={}", clientId, e);
        } finally {
            monitorService.recordMessageFlow(record);
        }
    }

    /**
     * 发送消息到设备
     */
    @Override
    public void sendToDevice(String clientId, String topic, byte[] payload) {
        try {
            if (!clientSessions.containsKey(clientId)) {
                log.warn("设备 {} 未连接，无法发送消息", clientId);
                return;
            }

            mqttServer.publish(clientId, topic, payload);
            log.debug("发送消息到设备成功: clientId={}, topic={}", clientId, topic);

        } catch (Exception e) {
            log.error("发送消息到设备失败: clientId={}, topic={}", clientId, topic, e);
            throw new RuntimeException("发送消息到设备失败", e);
        }
    }

    /**
     * 发送消息到设备（字符串格式）
     */
    @Override
    public void sendToDevice(String clientId, String topic, String message) {
        sendToDevice(clientId, topic, message.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 检查设备是否在线
     */
    @Override
    public boolean isDeviceOnline(String clientId) {
        ClientSession session = clientSessions.get(clientId);
        return session != null && session.getStatus() == ClientSession.Status.CONNECTED;
    }

    /**
     * 获取在线设备列表
     */
    @Override
    public Map<String, ClientSession> getOnlineDevices() {
        return new ConcurrentHashMap<>(clientSessions);
    }

    /**
     * 断开设备连接
     */
    @Override
    public void disconnectDevice(String clientId) {
        try {
            mqttServer.close(clientId);
            clientSessions.remove(clientId);
            log.info("主动断开设备连接: {}", clientId);
        } catch (Exception e) {
            log.error("断开设备连接失败: {}", clientId, e);
        }
    }

    /**
     * 从消息payload中解析clientId
     * 根据实际的消息格式进行调整
     */
    private String extractClientIdFromPayload(byte[] payload) {
        try {
            String payloadStr = new String(payload, StandardCharsets.UTF_8);
            // 假设消息格式为JSON，包含clientId字段
            // 实际实现需要根据您的消息格式来解析
            if (payloadStr.contains("\"clientId\"")) {
                // 使用JSON解析库解析clientId
                // 这里简化处理，实际应该使用JSON解析
                return extractJsonField(payloadStr, "clientId");
            }

            // 如果消息中没有clientId，可以尝试其他方式获取
            // 比如从主题中提取，或者维护主题与clientId的映射关系

        } catch (Exception e) {
            log.error("解析clientId失败", e);
        }
        return null;
    }

    /**
     * 简单的JSON字段提取（简化版，建议使用JSON库）
     */
    private String extractJsonField(String json, String field) {
        try {
            String fieldPattern = "\"" + field + "\":\"(.*?)\"";
            java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(fieldPattern);
            java.util.regex.Matcher matcher = pattern.matcher(json);
            if (matcher.find()) {
                return matcher.group(1);
            }
        } catch (Exception e) {
            log.error("提取JSON字段失败: field={}", field, e);
        }
        return null;
    }

    /**
     * 客户端会话信息
     */
    public static class ClientSession {
        private String clientId;
        private long connectTime;
        private long disconnectTime;
        private Status status;
        private long lastMessageTime;

        public enum Status {
            CONNECTED, DISCONNECTED
        }

        // getter and setter methods
        public String getClientId() { return clientId; }
        public void setClientId(String clientId) { this.clientId = clientId; }
        public long getConnectTime() { return connectTime; }
        public void setConnectTime(long connectTime) { this.connectTime = connectTime; }
        public long getDisconnectTime() { return disconnectTime; }
        public void setDisconnectTime(long disconnectTime) { this.disconnectTime = disconnectTime; }
        public Status getStatus() { return status; }
        public void setStatus(Status status) { this.status = status; }
        public long getLastMessageTime() { return lastMessageTime; }
        public void setLastMessageTime(long lastMessageTime) { this.lastMessageTime = lastMessageTime; }
    }
}
